/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package net.sf.tomp.slidestobeamer;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;

/**
 *
 * @author tomp
 */
public class SlidesToBeamerTransformer {

    private Templates slidesToBeamerXSLT;
    private Templates slidesToArticleXSLT;

    private String theme = "Warsaw";

    private boolean handout = true;

    private String author;

    private String title;

    private String subtitle;

    public String getSubtitle() {
        return subtitle;
    }

    public void setSubtitle(String subtitle) {
        this.subtitle = subtitle;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public boolean isHandout() {
        return handout;
    }

    public void setHandout(boolean handout) {
        this.handout = handout;
    }

    public String getTheme() {
        return theme;
    }

    public void setTheme(String theme) {
        this.theme = theme;
    }

    public SlidesToBeamerTransformer() throws TransformerConfigurationException {
        initFromResources();
    }

    private void initFromResources() throws TransformerConfigurationException {
        InputStream is1 = ClassLoader.getSystemResourceAsStream("net/sf/tomp/slidestobeamer/slides-to-beamer.xsl");
        InputStream is2 = ClassLoader.getSystemResourceAsStream("net/sf/tomp/slidestobeamer/slides-to-article.xsl");
        TransformerFactory factory = TransformerFactory.newInstance();
        slidesToBeamerXSLT = factory.newTemplates(new StreamSource(is1));
        slidesToArticleXSLT = factory.newTemplates(new StreamSource(is2));
    }

    private void transform(Templates templates, InputStream is, OutputStream os) throws IOException, TransformerConfigurationException, TransformerException {
        if (templates == null) {
            throw new NullPointerException("The transformer not yet initialized with an XSLT style.");
        }
        final Transformer newTransformer = templates.newTransformer();

        newTransformer.setParameter("author", getAuthor() == null ? "" : getAuthor());
        newTransformer.setParameter("title", getTitle() == null ? "" : getTitle());
        newTransformer.setParameter("subtitle", getSubtitle() == null ? "" : getSubtitle());
        newTransformer.setParameter("theme", getTheme());
        newTransformer.setParameter("handout", isHandout() ? 1 : 0);

        newTransformer.transform(new StreamSource(is), new StreamResult(os));
    }

    private void transform(Templates templates, File in, File out) throws IOException, TransformerConfigurationException, TransformerException {
        final FileInputStream fileInputStream = new FileInputStream(in);
        final FileOutputStream fileOutputStream = new FileOutputStream(out);
        transform(templates, fileInputStream, fileOutputStream);
        fileInputStream.close();
        fileOutputStream.close();
    }

    public void transformToArticle(File in, File out) throws IOException, TransformerConfigurationException, TransformerException {
        transform(slidesToArticleXSLT, in, out);
    }

    public void transformToBeamer(File in, File out) throws IOException, TransformerConfigurationException, TransformerException {
        transform(slidesToBeamerXSLT, in, out);
    }

    public void runPDFLaTeX(File f) throws IOException, InterruptedException {
        Process p = Runtime.getRuntime().exec("pdflatex " + f.getCanonicalPath());
        p.waitFor();
    }

    public void adjustLaTeXSource(File in, File out) throws IOException {
        LineIterator it = FileUtils.lineIterator(in);
        PrintStream ps = new PrintStream(out);
        try {
            while (it.hasNext()) {
                String line = it.nextLine();
                if (line.contains("\\includegraphics")) {
                    line = line.replaceAll("\\\\_", "\\_");
                }
                ps.println(line);
            }
        } finally {
            it.close();
            ps.close();
        }
    }

    public void adjustDocbookSource(File in, File out) throws IOException {
        LineIterator it = FileUtils.lineIterator(in);
        PrintStream ps = new PrintStream(out);
        boolean inListing = false;
        boolean atStart = true;
        try {
            while (it.hasNext()) {
                String line = it.nextLine();
                //System.out.println("Processing line:" + line);
                // split the very first line with XML heading into 2 lines
                // one with the heading/prolog, and the second with the rest
                if (atStart) {
                    if (line.matches("^\\<\\w+.*")) {
                        //System.out.println("now at root");
                        atStart = false; // now at root
                        ps.println(line);
                    } else if (line.matches("^\\<\\?.*")) {
                        //System.out.println("At prolog");
                        String[] splitHeading = line.split(">", 2);
                        ps.println(splitHeading[0] + ">");
                        if (splitHeading.length > 1) {
                            ps.println(splitHeading[1]);
                        }
                    } else if (line.matches("^\\<\\!DOCTYPE.*")) {
                        // at !DOCTYPE declaration, 1st line
                        //System.out.println("At DOCTYPE");
                        // do not print anything
                        if (!line.contains("SYSTEM")) {
                            // one more should be read
                            line = it.nextLine();
                            //System.out.println("At DOCTYPE 2nd line");
                        }
                        atStart = false; // now the root will follow
                    }
                } else {

                    if (line.contains("<programlisting") || line.contains("<screen")) {
                        inListing = true;
                    }
                    if (line.contains("</programlisting") || line.contains("</screen")) {
                        inListing = false;
                    }
                    if (inListing) {
                        ps.println(line);
                    } else {
                        line = line.replaceAll(" ", "~").replaceAll("\\s+", " ").replaceAll("\\\\", "\\/").replaceAll("\\_", "\\\\_").replaceAll("\\#", "\\\\#").replaceAll("\\-\\&gt\\;", "\\$\\\\to\\$");
                        ps.print(line);
                    }
                }
            }
        } finally {
            it.close();
            ps.close();
        }
    }
}